package net.i_tatami.slab.mazesearch.agent;



import java.awt.Point;
import java.util.ArrayList;

import net.i_tatami.slab.mazesearch.maze.Maze;
import net.i_tatami.slab.mazesearch.maze.VirtualWall;

public class PledgeMario extends Mario{

	public enum Action{
		KEEP,TURNRIGHT,TURNLEFT,UTURN
	}

	private Action action;
	
	private boolean onBuckTrack;
	
	private ArrayList<VirtualWall> vWalls;
	
	private ArrayList<Point> path;

	public PledgeMario(Maze maze){
		super(maze);
		this.vWalls = new ArrayList<VirtualWall>();
		this.path = new ArrayList<Point>();
		this.direction = Maze.SOUTH; 
		this.location = maze.getStart();
		sense();
	}
	
	public void step(){
		sense();
		makeWall();
		decideAction();
		takeAction();
	}
	
	public void makeBehindWall(){
		switch(this.direction){
		case Maze.NORTH :
			this.vWalls.add(new VirtualWall((Point) this.location.clone(), new Point(this.location.x, this.location.y+1)));
			this.vWalls.add(new VirtualWall(new Point(this.location.x, this.location.y+1), (Point) this.location.clone()));
			break;
		case Maze.SOUTH:
			this.vWalls.add(new VirtualWall((Point) this.location.clone(), new Point(this.location.x, this.location.y-1)));
			this.vWalls.add(new VirtualWall(new Point(this.location.x, this.location.y-1), (Point) this.location.clone()));
			break;
		case Maze.WEST:
			this.vWalls.add(new VirtualWall((Point) this.location.clone(), new Point(this.location.x+1, this.location.y)));
			this.vWalls.add(new VirtualWall(new Point(this.location.x+1, this.location.y), (Point) this.location.clone()));
			break;
		case Maze.EAST:
			this.vWalls.add(new VirtualWall((Point) this.location.clone(), new Point(this.location.x-1, this.location.y)));
			this.vWalls.add(new VirtualWall(new Point(this.location.x-1, this.location.y), (Point) this.location.clone()));
			break;
		}
		this.onBuckTrack = false;
	}
	
	public void makeWall(){
		if(onBuckTrack){
			boolean frontWall = false;
			boolean leftWall = false;
			boolean rightWall = false;

			switch(this.direction){	
			case Maze.NORTH :
				leftWall = isVWall(location, new Point(location.x-1, location.y));
				frontWall = isVWall(location, new Point(location.x, location.y-1));
				rightWall = isVWall(location, new Point(location.x+1, location.y));
				break;
			case Maze.SOUTH:
				leftWall = isVWall(location, new Point(location.x+1, location.y));
				frontWall = isVWall(location, new Point(location.x, location.y+1));
				rightWall = isVWall(location, new Point(location.x-1, location.y));
				break;
			case Maze.WEST:
				leftWall = isVWall(location, new Point(location.x, location.y+1));
				frontWall = isVWall(location, new Point(location.x-1, location.y));
				rightWall = isVWall(location, new Point(location.x, location.y-1));
				break;
			case Maze.EAST:
				leftWall = isVWall(location, new Point(location.x, location.y-1));
				frontWall = isVWall(location, new Point(location.x+1, location.y));
				rightWall = isVWall(location, new Point(location.x, location.y+1));
				break;
			}
			if((leftSensorInfo == Maze.ROAD && !leftWall) && (frontSensorInfo == Maze.ROAD && !frontWall)){
				makeBehindWall();
			}
			else if((leftSensorInfo == Maze.ROAD && !leftWall) && (rightSensorInfo == Maze.ROAD && !rightWall)){
				makeBehindWall();
			}
			else if((frontSensorInfo == Maze.ROAD && !frontWall) && (rightSensorInfo == Maze.ROAD && !rightWall)){
				makeBehindWall();
			}
		}
		else{
			Point left = null;
			Point front = null;
			Point right = null;

			switch(this.direction){
			case Maze.NORTH :
				left = new Point(this.location.x-1, this.location.y);
				front = new Point(this.location.x, this.location.y-1);
				right = new Point(this.location.x+1, this.location.y);
				if(this.path.contains(left)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), left));
					this.vWalls.add(new VirtualWall(left, (Point) this.location.clone()));
				}
				if(this.path.contains(front)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), front));
					this.vWalls.add(new VirtualWall(front, (Point) this.location.clone()));
				}
				if(this.path.contains(right)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), right));
					this.vWalls.add(new VirtualWall(right, (Point) this.location.clone()));
				}
				break;
			case Maze.SOUTH:
				left = new Point(this.location.x+1, this.location.y);
				front = new Point(this.location.x, this.location.y+1);
				right = new Point(this.location.x-1, this.location.y);
				if(this.path.contains(left)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), left));
					this.vWalls.add(new VirtualWall(left, (Point) this.location.clone()));
				}
				if(this.path.contains(front)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), front));
					this.vWalls.add(new VirtualWall(front, (Point) this.location.clone()));
				}
				if(this.path.contains(right)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), right));
					this.vWalls.add(new VirtualWall(right, (Point) this.location.clone()));
				}
				break;
			case Maze.WEST:
				left = new Point(this.location.x, this.location.y+1);
				front = new Point(this.location.x-1, this.location.y);
				right = new Point(this.location.x, this.location.y-1);
				if(this.path.contains(left)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), left));
					this.vWalls.add(new VirtualWall(left, (Point) this.location.clone()));
				}
				if(this.path.contains(front)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), front));
					this.vWalls.add(new VirtualWall(front, (Point) this.location.clone()));
				}
				if(this.path.contains(right)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), right));
					this.vWalls.add(new VirtualWall(right, (Point) this.location.clone()));
				}
				break;
			case Maze.EAST:
				left = new Point(this.location.x, this.location.y-1);
				front = new Point(this.location.x+1, this.location.y);
				right = new Point(this.location.x, this.location.y+1);
				if(this.path.contains(left)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), left));
					this.vWalls.add(new VirtualWall(left, (Point) this.location.clone()));
				}
				if(this.path.contains(front)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), front));
					this.vWalls.add(new VirtualWall(front, (Point) this.location.clone()));
				}
				if(this.path.contains(right)){
					this.vWalls.add(new VirtualWall((Point) this.location.clone(), right));
					this.vWalls.add(new VirtualWall(right, (Point) this.location.clone()));
				}
				break;
			}
		}
	}

	public void decideAction(){
		boolean frontWall = false;
		boolean leftWall = false;
		boolean rightWall = false;

		switch(this.direction){	
		case Maze.NORTH :
			leftWall = isVWall(location, new Point(location.x-1, location.y));
			frontWall = isVWall(location, new Point(location.x, location.y-1));
			rightWall = isVWall(location, new Point(location.x+1, location.y));
			break;
		case Maze.SOUTH:
			leftWall = isVWall(location, new Point(location.x+1, location.y));
			frontWall = isVWall(location, new Point(location.x, location.y+1));
			rightWall = isVWall(location, new Point(location.x-1, location.y));
			break;
		case Maze.WEST:
			leftWall = isVWall(location, new Point(location.x, location.y+1));
			frontWall = isVWall(location, new Point(location.x-1, location.y));
			rightWall = isVWall(location, new Point(location.x, location.y-1));
			break;
		case Maze.EAST:
			leftWall = isVWall(location, new Point(location.x, location.y-1));
			frontWall = isVWall(location, new Point(location.x+1, location.y));
			rightWall = isVWall(location, new Point(location.x, location.y+1));
			break;
		}
		
		if((leftSensorInfo == Maze.ROAD && !leftWall)){
			this.action = Action.TURNLEFT;
		}
		else if((leftSensorInfo == Maze.WALL || leftWall) && (frontSensorInfo == Maze.ROAD && !frontWall)){
			this.action = Action.KEEP;
		}
		else if((leftSensorInfo == Maze.WALL || leftWall) && (frontSensorInfo == Maze.WALL || frontWall) && (rightSensorInfo == Maze.ROAD && !rightWall)){
			this.action = Action.TURNRIGHT;
		}
		else{
			this.action = Action.UTURN;
			onBuckTrack = true;
		}
	}

	public void takeAction(){
		this.path.add((Point) this.location.clone());
		switch(action){
		case TURNLEFT:
			switch(direction){
			case Maze.NORTH:
				this.direction = Maze.WEST;
				break;
			case Maze.SOUTH:
				this.direction = Maze.EAST;
				break;
			case Maze.WEST:
				this.direction = Maze.SOUTH;
				break;
			case Maze.EAST:
				this.direction = Maze.NORTH;
				break;
			}
			break;
		case TURNRIGHT:
			switch(direction){
			case Maze.NORTH:
				this.direction = Maze.EAST;
				break;
			case Maze.SOUTH:
				this.direction = Maze.WEST;
				break;
			case Maze.WEST:
				this.direction = Maze.NORTH;
				break;
			case Maze.EAST:
				this.direction = Maze.SOUTH;
				break;
			}
			break;
		case UTURN:
			switch(direction){
			case Maze.NORTH:
				this.direction = Maze.SOUTH;
				break;
			case Maze.SOUTH:
				this.direction = Maze.NORTH;
				break;
			case Maze.WEST:
				this.direction = Maze.EAST;
				break;
			case Maze.EAST:
				this.direction = Maze.WEST;
				break;
			}
			break;
		}
		switch(direction){
		case Maze.NORTH:
			this.location.y--;
			break;
		case Maze.SOUTH:
			this.location.y++;
			break;
		case Maze.WEST:
			this.location.x--;
			break;
		case Maze.EAST:
			this.location.x++;
			break;
		}
	}
	
	private boolean isVWall(Point from, Point next){
		boolean result = false;
		for(VirtualWall vWall : this.vWalls){
			if(vWall.getFrom().equals(from) && vWall.getNext().equals(next)){
				result = true;
			}
		}
		return result;
	}

	public ArrayList<VirtualWall> getVWalls() {
		return vWalls;
	}

	public ArrayList<Point> getPath() {
		return path;
	}
}
